home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-10 | 30.4 KB | 1,203 lines |
- /*
- * fmonitor.r -- mmout, mmpause, mmshow, EvSetup, EvSelect, EvGet
- *
- * This file contains event monitoring code.
- *
- * Much of this code is contingent on the definition of MemMon (memory
- * monitoring) and EventMon (event monitoring). Memory monitoring came
- * first and normally is defined in all implementations of Icon. It also
- * is a supported feature with various visualization tools. (See the
- * directory "memmon", which is parallel to this one.) Event monitoring is
- * more recent and is stil experimental. It normally is not enabled. Memory
- * monitoring is a subset of event monitoring.
- *
- * When MemMon or EventMon is undefined, most of the "MMxxxx" and "EVxxxx"
- * entry points are defined as null macros in monitor.h.
- *
- * See monitor.h for important definitions and for the interaction between
- * MemMon and Eventmon.
- */
-
-
- #ifdef MemMon
-
- /*
- * Prototypes.
- */
-
- hidden novalue evcmd Params((word addr, word len, int c));
- hidden novalue evdec Params((uword n));
- hidden novalue evforget Params((noargs));
- hidden novalue etvalue Params((word n, int c));
-
- #ifdef EventMon
- hidden novalue etqvalue Params((word n, int c));
- int evstring Params((char *buf, int buflen, int tc));
- #endif /* EventMon */
-
- hidden novalue evnewline Params((noargs));
- hidden novalue mmrefresh Params((noargs));
- hidden novalue mmsizes Params((int c));
- hidden novalue mmstatic Params((noargs));
-
- FILE *monfile = NULL; /* output file pointer */
-
- static char *monname = NULL; /* output file name */
-
- #ifdef EventMon
- union { /* clock ticker -- keep in sync w/ interp.c */
- unsigned short s[4]; /* four counters */
- unsigned long l[2]; /* two longs are easier to check */
- } ticker;
- unsigned long oldtick; /* previous sum of the two longs */
- #endif /* EventMon */
-
- static word llen = 0; /* current output line length */
-
- static char typech[MaxType+1]; /* output character for each type */
-
- /* Define size of curvalue table, and bias needed to access it. */
- /* Assumes all type codes are printable characters (or space). */
- /* Smaller table is used if not EBCDIC. */
- #if !EBCDIC
- #define CurSize (127 - ' ')
- #define CurBias ' '
- #else /* !EBCDIC */
- #define CurSize 256
- #define CurBias 0
- #endif /* !EBCDIC */
-
- static word curvalue[CurSize]; /* current length for each output character */
-
- /* line limit: start a new line when a command goes beyond this column */
- #define LLIM 70
-
- /* evchar(c): output character c and update the column counter */
- #define evchar(c) (llen++,putc((c),monfile))
-
- /* evspace(): output unneeded whitespace whitespace following a command */
- /* define as "evchar(' ')" for readable files, or as "0" for compact ones */
- #define evspace() 0
-
- /*
- * evseparate(): output either a space or a newline depending on spacing
- * requirements
- */
- #define evseparate() if (llen >= LLIM) evnewline(); else evchar(' ');
-
-
- "mmout(s) - write the given string to the MemMon file."
-
- function{1} mmout(s)
- if !def:C_string(s, "") then
- runerr(103, s)
- abstract {
- return null
- }
- inline {
- MMOut("", s);
- return nulldesc;
- }
- end
-
-
- "mmpause(s) - pause MemMon displaying string s."
-
- function{1} mmpause(s)
- if !def:C_string(s, "") then
- runerr(103, s)
- abstract {
- return null
- }
- inline {
- MMOut("; ", s[0] ? s : "programmed pause");
- return nulldesc;
- }
- end
-
-
- "mmshow(x,s) - alter MemMon display of x depending on s."
-
- function{1} mmshow(x, s)
-
- if !def:string(s, emptystr) then
- runerr(103, s)
- abstract {
- return null
- }
- body {
- register word i, j, d;
- register union block *bp, *ep;
- char c;
- struct b_slots *seg;
-
- if (StrLen(s) == 0)
- c = '\0';
- else
- c = *StrLoc(s);
- MMShow(&x,c);
- switch (Type(x)) {
- case T_List:
- bp = BlkLoc(x);
- for (bp = bp->list.listhead; bp != NULL; bp = bp->lelem.listnext) {
- x.dword = D_Lelem;
- BlkLoc(x) = bp;
- MMShow(&x, c);
- }
- break;
- case T_Set:
- case T_Table:
- d = (Type(x) == T_Set) ? D_Selem : D_Telem;
- bp = BlkLoc(x);
- for (i = 0; i < HSegs && (seg = bp->table.hdir[i]) != NULL; i++) {
- x.dword = D_Slots;
- BlkLoc(x) = (union block *)seg;
- MMShow(&x, c);
- for (j = segsize[i] - 1; j >= 0; j--) {
- x.dword = d;
- for (ep = seg->hslots[j]; ep != NULL; ep = ep->telem.clink) {
- BlkLoc(x) = ep;
- MMShow(&x, c);
- }
- }
- }
- break;
- }
-
- return nulldesc;
- }
- end
-
- #ifdef EventProc
- /*
- * EvSetup, EvSelect, EvGet - user functions for reading event streams.
- */
- FILE *evfile; /* input file */
-
- word evctx; /* current event context */
- word wantctx = 1; /* nonzero if this context is selected */
- word evdepth; /* current nesting depth */
- word evstk[MaxEvNest+1]; /* nesting stack */
-
- int nevsel; /* number of event contexts */
- char *evsel; /* nonzero entry for each context selected */
-
- word evhist[256]; /* history of previous values */
-
- dptr EvContext; /* pointer to EvContext global */
- dptr EvCode; /* pointer to EvCode global */
- dptr EvValue; /* pointer to EvValue global */
- dptr EvGivenValue; /* pointer to EvGivenValue global */
-
- /*
- * MT code is written as if there were a global variable EStream:
- */
- #ifdef MultiThread
- dptr EStream; /* pointer to EventStream global */
- #endif /* MultiThread */
-
-
- "EvSetup(f,i) - initialize to read event tokens from file f."
- /*
- * i is the highest context number that will be allowed.
- * Globals EvContext, EvCode, EvValue, and EvGivenValue must exist.
- */
-
- function{1} EvSetup(f,n)
-
- abstract {
- return null
- }
-
- if !is:file(f) then
- runerr(105, f)
-
- /*
- * n must be a positive integer.
- */
- if !cnv:C_integer(n) then
- runerr(101, n)
- body {
- word i;
- struct descrip d1, d2, d3, d4, d5;
-
- if (n <= 0) {
- irunerr(205, n);
- errorfail;
- }
- nevsel = n;
-
- /*
- * Find the globals.
- */
- if (getvar("EvContext", &d1) != Succeeded
- || getvar("EvCode", &d2) != Succeeded
- || getvar("EvValue", &d3) != Succeeded
- || getvar("EvGivenValue", &d4) != Succeeded)
- runerr(126);
- EvContext = VarLoc(d1);
- EvCode = VarLoc(d2);
- EvValue = VarLoc(d3);
- EvGivenValue = VarLoc(d4);
-
- /*
- * Initialize the selection table and save the file pointer.
- */
- evsel = (char *)malloc((msize)(nevsel + 1));
- if (evsel == NULL)
- runerr(305);
- for (i = 0; i <= nevsel; i++)
- evsel[i] = 1;
-
-
- evfile = BlkLoc(f)->file.fd;
-
- return nulldesc;
- }
- end
-
-
- "EvSelect(i1, i2,...) - configure EvGet to return only certain event contexts."
-
- function{1} EvSelect(x[nargs])
-
- abstract {
- return null
- }
- body {
- register C_integer i;
- C_integer j;
- /*
- * Be sure EvSetup was called.
- */
- if (evfile == NULL)
- runerr(126);
-
- if (nargs == 0) {
- /*
- * With no arguments, enable all contexts.
- */
- for (i = 0; i <= nevsel; i++)
- evsel[i] = 1;
- wantctx = (evctx <= nevsel);
- return nulldesc;
- }
- else {
- /*
- * With explicit arguments, disable all contexts, then enable
- * as selected.
- */
- for (i = 0; i <= nevsel; i++)
- evsel[i] = 0;
- for (i = 0; i < nargs; i++) {
- if (!cnv:C_integer(x[i], j))
- runerr(101, x[i]);
- if (j < 0 || j > nevsel)
- runerr(205, x[i]);
- evsel[j] = 1;
- }
- wantctx = (evctx <= nevsel && evsel[evctx]);
- return nulldesc;
- }
- }
- end
-
-
- "EvGet(c) - read through the next event token having a code matched by cset c."
-
- /*
- * EvGet returns the code of the matched token. These globals are also set:
- * EvContext context number
- * EvCode token code
- * EvValue token value, with implicit value if omitted
- * EvGivenValue token value, &null if omitted
- */
- function{0,1} EvGet(cs)
- if !def:tmp_cset(cs,fullcs) then
- runerr(104,cs)
-
- abstract {
- return string
- }
-
- body {
- register int c;
- register word n, tkctx, wanted;
- char sbuf[MaxEvString];
- word len;
-
- /*
- * Be sure EvSetup was called.
- */
- if (evfile == NULL)
- runerr(126);
-
- /*
- * Loop until we read an event matched by the cset.
- */
- for (wanted = 0; !wanted; ) {
- /*
- * Parse the token up through the event code character.
- */
- tkctx = evctx; /* context of this token */
- n = -1; /* -1 indicates no integer value */
- len = -1; /* -1 indicates no string value */
-
-
- c = getc(evfile);
- while (isspace(c)) /* skip leading whitespace */
- c = getc(evfile);
- if (isdigit(c)) { /* if digit, build up count */
- n = c - '0';
- while (isdigit(c = getc(evfile)))
- n = 10 * n + c - '0';
- }
- else if (c == '"') { /* if quote, read string value */
- len = evstring (sbuf, MaxEvString, '"');
- c = getc(evfile); /* load following character */
- }
-
- while (isspace(c)) /* skip whitespace after the value */
- c = getc(evfile);
-
-
- /*
- * Handle according to the code character now in c.
- * Decide whether the event is wanted.
- */
- switch (c) {
- case EOF:
- *EvContext = *EvCode = *EvValue = *EvGivenValue = nulldesc;
- fail;
- case E_Comment:
- case E_Pause:
- len = evstring (sbuf, MaxEvString, '\n');
- wanted = wantctx && Testb(c, cs);
- break;
- case E_Start: /* start (push) context */
- if (evdepth < MaxEvNest)
- evstk[++evdepth] = evctx = tkctx = n;
- wantctx = (evctx <= nevsel && evsel[evctx]);
- wanted = wantctx && Testb(c, cs);
- break;
- case E_End: /* end (pop) context */
- wanted = wantctx && Testb(c, cs);
- if (evstk[evdepth] == n && evdepth > 0)
- evctx = evstk[--evdepth];
- wantctx = (evctx <= nevsel && evsel[evctx]);
- break;
- default:
- wanted = wantctx && Testb(c, cs);
- break;
- }
- }
-
- /*
- * This event is wanted. Set the globals and return.
- */
- MakeInt(tkctx, EvContext);
-
- if (len >= 0) { /* if quoted value given */
- StrLen(*EvGivenValue) = len;
- Protect(StrLoc(*EvGivenValue) = alcstr(sbuf, len), runerr(0));
- *EvValue = *EvGivenValue; /* store in EvGivenValue and EvValue */
- }
- else if (n >= 0) { /* if numeric value given */
- evhist[c] = n; /* remember it */
- MakeInt(n, EvGivenValue); /* store in EvGivenValue and EvValue */
- *EvValue = *EvGivenValue;
- }
- else { /* if no value */
- *EvGivenValue = nulldesc; /* set EvGivenValue to null */
- MakeInt(evhist[c], EvValue); /* store previous value as EvValue */
- }
-
- StrLen(*EvCode) = 1;
- StrLoc(*EvCode) = &allchars[FromAscii(c) & 0xFF];
- return *EvCode;
- }
- end
-
- /*
- * evstring (buf, buflen, tc) - read event string into buf.
- *
- * Characters from the event stream are read until the terminator character
- * tc is read. The characters excluding the terminator are stored in the
- * buffer buf of length buflen; excess characters are discarded. The number
- * of characters stored is returned.
- */
- int evstring (buf, buflen, tc)
- char *buf;
- int buflen, tc;
- {
- register int c;
- register word n;
-
- n = 0;
- while ((c = getc(evfile)) != tc && c != EOF)
- if (n < buflen)
- buf[n++] = c;
- return n;
- }
- #endif /* EventProc */
-
- /*
- * EVInit(exename,outname) - initialization.
- *
- * Event monitoring is activated if one of the environment variables EVENTMON
- * or MEMMON is non-null, depending on which type of monitoring is configured.
- * The environment variable names the output file; or, under implementations
- * that support pipes, a value beginning with "|" specifies a command to which
- * the output is piped.
- *
- * Monitoring can also be activated by the -E option on the iconx command
- * line, in which case outname is nonnull and overrides any environment
- * setting.
- *
- * If monitoring is defined on a system lacking environment variables,
- * monitoring is always activated and output is to the file "eventmon.out"
- * if outname does not specify a different file.
- */
-
- novalue EVInit(exename,outname)
- char *exename;
- char *outname;
- {
- int i;
- FILE *f;
- char time_buf[26];
-
- #ifdef EventMon
- char *name = EVENTMON;
- #else /* EventMon */
- char *name = MEMMON;
- #endif /* EventMon */
-
-
- /*
- * Initialize the typech array, which is used if either file-based
- * or MT-based event monitoring is enabled.
- */
-
- for (i = 0; i <= MaxType; i++)
- typech[i] = '?'; /* initialize with error character */
-
- #ifdef LargeInts
- typech[T_Lrgint] = E_Lrgint; /* long integer */
- #endif /* LargeInts */
-
- typech[T_Real] = E_Real; /* real number */
- typech[T_Cset] = E_Cset; /* cset */
- typech[T_File] = E_File; /* file block */
- typech[T_Record] = E_Record; /* record block */
- typech[T_Tvsubs] = E_Tvsubs; /* substring trapped variable */
- typech[T_External]= E_External; /* external block */
- typech[T_List] = E_List; /* list header block */
- typech[T_Lelem] = E_Lelem; /* list element block */
- typech[T_Table] = E_Table; /* table header block */
- typech[T_Telem] = E_Telem; /* table element block */
- typech[T_Tvtbl] = E_Tvtbl; /* table elem trapped variable*/
- typech[T_Set] = E_Set; /* set header block */
- typech[T_Selem] = E_Selem; /* set element block */
- typech[T_Slots] = E_Slots; /* set/table hash slots */
- typech[T_Coexpr] = E_Coexpr; /* co-expression block (static) */
- typech[T_Refresh] = E_Refresh; /* co-expression refresh block */
-
- /*
- * codes used elsewhere but not shown here:
- * in the static region: E_Alien = alien (malloc block)
- * in the static region: E_Free = free
- * in the string region: E_String = string
- */
-
-
- /*
- * Now, if file-based event monitoring is desired, turn it on.
- * Look up the MEMMON/EVENTMON environment variable if outname is NULL.
- */
-
- if (outname)
- monname = outname;
- else {
-
- #ifdef EnvVars
- monname = getenv(name);
- if (monname == NULL || strlen(monname) == 0)
- return;
- #else /* EnvVars */
- monname = "monitor.out";
- #endif /* EnvVars */
-
- }
-
- #ifdef Pipes
- if (monname[0] == '|')
- f = popen(monname+1, WriteText);
- else
- #endif /* Pipes */
-
- {
- if (monname[0] == '-' && monname[1] == '\0')
- f = stdout;
- else
- f = fopen(monname, WriteText);
- }
-
- if (f == NULL) {
- fprintf(stderr, "%s: cannot open %s\n", name, monname);
- fflush(stderr);
- exit(ErrorExit);
- }
-
-
- #ifdef EventMon
- #if UNIX
- /*
- * Call profil(2) to enable program counter profiling. We use the smallest
- * allowable scale factor in order to minimize the number of counters;
- * we assume that the text of iconx does not exceed 256K and so we use
- * four bins. One of these four bins will be incremented every system
- * clock tick (typically 4 to 20 ms).
- *
- * Take your local profil(2) man page with a grain of salt. All the systems
- * we tested really maintain 16-bit counters despite what the man pages say.
- * Some also say that a scale factor of two maps everything to one counter;
- * that is believed to be a no-longer-correct statement dating from the days
- * when the maximum program size was 64K.
- *
- * The reference to EVInit below just obtains an arbitrary address within
- * the text segment.
- */
- profil(ticker.s, sizeof(ticker.s), (int) EVInit & ~0x3FFFF, 2);
- #endif /* UNIX */
- #endif /* EventMon */
-
- getctime(time_buf);
- fprintf(f, "## Icon event stream, Version %s\n", Eversion);
- fprintf(f, "#\n");
- fprintf(f, "# program: %s\n", exename);
- fprintf(f, "# date: %s", time_buf);
-
- /*
- * Set monfile to indicate that monitoring is active. Don't set it earlier
- * than this, or we'll loop trying to trace the garbage collection that
- * creates the buffer space.
- */
- monfile = f;
- }
-
- /*
- * EVSetup() - Set up storage information.
- */
- novalue EVSetup()
- {
-
- if (!EventStream)
- return;
- mmrefresh(); /* show current state */
- fflush(monfile); /* force it out */
- }
-
- /*
- * EVTerm(n, part2) - terminate memory monitoring.
- * The error message for n and part2 are concatentated to form an explanatory
- * message.
- */
-
- novalue EVTerm(n, part2)
- int n;
- char *part2;
- {
- FILE *f;
- char part1[40];
-
- if (!EventStream)
- return;
- if (n > 0)
- sprintf(part1,"Run-time error %d: ",n);
- else
- part1[0] = '\0';
- if (part2 == NULL)
- part2 = "";
- evnewline();
- mmsizes('='); /* make a final check on region sizes */
-
- #ifdef EventMon
- EVVal(C_Eval,E_End);
- fprintf(monfile,"\n");
- #endif /* EventMon */
-
- if (*part1 || *part2) /* if any reason given, write it as comment */
- fprintf(monfile, "# %s%s\n", part1, part2);
-
- f = monfile;
- monfile = NULL; /* so we don't try to show the freeing of the buffer */
-
- #ifdef Pipes
- if (monname[0] == '|')
- pclose(f);
- else
- #endif /* Pipes */
- fclose(f);
- }
-
- /*
- * MMStat(a, n, c) - note static block at a, length n, represented by char 'c'.
- * Output values are in basic units (typically words).
- */
- novalue MMStat(a, n, c)
- char *a;
- word n;
- int c;
- {
-
- #ifndef FixedRegions
- if (!EventStream)
- return;
- evcmd(DiffPtrs(a, statbase) / MMUnits, n / MMUnits, c);
- #endif /* FixedRegions */
-
- }
-
- /*
- * MMAlc(len, type) - note an allocation at the end of the block region.
- *
- * If len is negative, it's a deallocation, and the type doesn't matter.
- */
-
- novalue MMAlc(len, type)
- word len;
- int type;
- {
- if (len < 0)
- evcmd((word)-1, -len / MMUnits, E_BlkDeAlc);
- else
- EVVal(len / MMUnits, typech[type]);
- }
-
- /*
- * MMStr(len) - note a string allocation at the end of the string region.
- *
- * If len is negative, it's a deallocation.
- */
-
- novalue MMStr(slen)
- word slen;
- {
- if (slen > 0)
- EVVal(slen, E_String);
- else if (slen < 0)
- evcmd((word)-1, -slen, E_StrDeAlc);
- }
-
- /*
- * MMBGC() - begin garbage collection.
- */
-
- novalue MMBGC(region)
- int region;
- {
- if (!EventStream)
- return;
-
- mmsizes('='); /* write current sizes */
-
- #ifdef EventMon
- EVVal(C_Collect,E_Start);
- EVVal(region, E_Region);
- EVVal(C_Mark,E_Start);
- llen += 7;
- #else /* EventMon */
- fprintf(monfile, "%d{\n", region); /* indicate start of g.c. */
- #endif /* EventMon */
-
- fflush(monfile);
- evforget(); /* clear memory of block sizes */
- }
-
- /*
- * MMEGC() - end garbage collection.
- */
-
- novalue MMEGC()
- {
- if (!EventStream)
- return;
- evnewline();
-
- #ifdef EventMon
- EVVal(C_Mark, E_End);
- #else /* EventMon */
- fprintf(monfile, "}\n"); /* indicate end of marking */
- #endif /* EventMon */
-
- mmrefresh(); /* redraw regions after compaction */
-
- #ifdef EventMon
- EVVal(C_Collect, E_End); /* indicate end of g.c. */
- #else /* EventMon */
- fprintf(monfile, "!\n"); /* indicate end of g.c. */
- #endif /* EventMon */
-
- fflush(monfile);
- }
-
- /*
- * MMMark(block, type) - mark indicated block during garbage collection.
- */
-
- novalue MMMark(block, type)
- char *block;
- int type;
- {
- if (!EventStream)
- return;
- evcmd(DiffPtrs(block, blkbase) / MMUnits, (word)BlkSize(block) / MMUnits,
- typech[type]);
- }
-
- /*
- * MMSMark - Mark String.
- */
-
- novalue MMSMark(saddr, slen)
- char *saddr;
- word slen;
- {
- if (!EventStream)
- return;
- evcmd(DiffPtrs(saddr, strbase), slen, E_String);
- }
-
- /*
- * MMOut(prefix, msg) - write the prefix and message to the MemMon output file.
- */
-
- novalue MMOut(prefix, msg)
- char *prefix, *msg;
- {
- if (!EventStream)
- return;
- evnewline();
- fprintf(monfile, "%s%s\n", prefix, msg);
- }
-
- /*
- * MMShow(d, colr) - redraw string or block d, specifying the color character.
- */
-
- novalue MMShow(d, colr)
- dptr d;
- int colr;
- {
- char *block;
- uword addr;
- word len;
- char cmd, tch;
-
- if (!EventStream)
- return;
- if (colr == '\0')
- colr = 'r'; /* default color is 'r' (redraw) */
-
- if (Qual(*d)) {
- /*
- * Show a string.
- */
- if (!InRange(strbase,StrLoc(*d),strend))
- return; /* ignore if outside string region */
- addr = DiffPtrs(StrLoc(*d), strbase);
- len = StrLen(*d);
- cmd = '$';
- tch = E_String;
- }
- else if (Type(*d)==T_Coexpr) {
- /*
- * Show a co-expression block, which will be in the static region.
- */
- block = (char *)BlkLoc(*d);
- addr = DiffPtrs(block, statbase) / MMUnits;
- len = BlkSize(block) / MMUnits;
- cmd = 'Y';
- tch = typech[T_Coexpr];
- }
- else if (Pointer(*d)) {
- /*
- * Show object in the block region.
- */
- block = (char *)BlkLoc(*d);
- if (!InRange(blkbase,block,blkfree))
- return; /* ignore if outside block region */
- addr = DiffPtrs(block, blkbase) / MMUnits;
- len = BlkSize(block) / MMUnits;
- cmd = '%';
- tch = typech[Type(*d)];
- }
-
- if (llen+5 >= LLIM) /* allow extra room; this will be a long one */
- evnewline();
-
- evdec(addr); /* address */
- evchar(E_Offset);
-
- #ifdef EventMon
- evchar('"');
- #endif /* EventMon */
-
- etvalue(len, cmd); /* length, and $ Y or % command */
- evchar(colr); /* color flag */
- evchar(tch); /* block type character */
-
- #ifdef EventMon
- evchar('"');
- evchar(E_Highlight);
- #endif /* EventMon */
-
- if (llen >= LLIM)
- evnewline();
- else
- evspace();
- }
-
- /*
- * mmrefresh() - redraw screen, initially or after garbage collection.
- */
-
- static novalue mmrefresh()
- {
- char *p;
- word n;
-
- evnewline();
- mmsizes('<'); /* signal start of screen refresh */
- evnewline();
- evforget(); /* clear memory of past sizes */
- mmstatic(); /* show the static region */
- evnewline();
- for (p = blkbase; p < blkfree; p += n)
- MMAlc(n = BlkSize(p), (int)BlkType(p));/* block region */
- evnewline();
- MMStr(DiffPtrs(strfree, strbase)); /* string region */
- evnewline();
-
- #ifdef EventMon
- EVVal(C_Redraw, E_End); /* signal redrawing */
- #else /* EventMon */
- fprintf(monfile, ">\n"); /* signal end of refresh */
- #endif /* EventMon */
-
- mmsizes('='); /* confirm region sizes */
- evforget(); /* clear memory of past sizes */
- }
-
- /*
- * mmstatic() - recap the static region (stack, coexprs, aliens, free)
- * (this function is empty under FixedRegions)
- */
- static novalue mmstatic()
- {
- #ifndef FixedRegions
- HEADER *p;
- char *a;
- int h;
- word n;
-
- for (p = (HEADER *)statbase; (uword)p < (uword)(HEADER *)statfree;
- p += p->s.bsize) {
- a = (char *)(p + 1);
- n = (p->s.bsize - 1) * sizeof(HEADER);
- h = *(int *)a;
- if (h == T_Coexpr)
- MMStat(a, n, E_Coexpr); /* co-expression block */
- else if (h == FREEMAGIC)
- MMStat(a, n, E_Free); /* free block */
- else
- MMStat(a, n, E_Alien); /* alien block */
- }
- a = (char *)p;
- if (a < statend)
- MMStat(a, (word)(statend-a), E_Free);/* rest of static region is free */
- #endif /* FixedRegions */
- }
-
- /*
- * mmsizes(c) - output current region sizes, with initial character c.
- * If c is '<', the unit size is written ahead of it.
- */
- static novalue mmsizes(c)
- int c;
- {
- evnewline();
-
- #ifdef EventMon
- if (c == '<')
- EVVal(C_Refresh, E_Start);
- else
- EVVal(C_Verify, E_Start);
- fprintf(monfile, "%lu%c%lu%c%lu%c%lu%c%lu%c%lu%c%lu%c%lu%c%lu%c",
- /* static region; show as full, actual amount is unknown */
- (unsigned long)statbase,
- E_Base,
- (unsigned long)DiffPtrs(statend, statbase),
- E_Used,
- (unsigned long)DiffPtrs(statend, statbase),
- E_Size,
- /* string region */
- (unsigned long)strbase,
- E_Base,
- (unsigned long)DiffPtrs(strfree, strbase),
- E_Used,
- (unsigned long)DiffPtrs(strend, strbase),
- E_Size,
- /* block region */
- (unsigned long)blkbase,
- E_Base,
- (unsigned long)DiffPtrs(blkfree, blkbase),
- E_Used,
- (unsigned long)DiffPtrs(blkend, blkbase),
- E_Size);
- #else /* EventMon */
- if (c == '<')
- fprintf(monfile,"%d%c\n", MMUnits, c);
- else
- fprintf(monfile, "%c ", c);
- fprintf(monfile, "%lu:%lu/%lu %lu:%lu/%lu %lu:%lu/%lu\n",
-
- /* static region; show as full, actual amount is unknown */
- (unsigned long)statbase,
- (unsigned long)DiffPtrs(statend, statbase),
- (unsigned long)DiffPtrs(statend, statbase),
- /* string region */
- (unsigned long)strbase,
- (unsigned long)DiffPtrs(strfree, strbase),
- (unsigned long)DiffPtrs(strend, strbase),
- /* block region */
- (unsigned long)blkbase,
- (unsigned long)DiffPtrs(blkfree, blkbase),
- (unsigned long)DiffPtrs(blkend, blkbase));
- #endif /* EventMon */
-
- #ifdef EventMon
- if (c == '<') {
- EVVal(C_Refresh, E_End);
- fprintf(monfile,"\n");
- EVVal(C_Redraw, E_Start);
- llen = 3;
- }
- else {
- EVVal(C_Verify, E_End);
- fprintf(monfile,"\n");
- }
- #else /* EventMon */
- if (c == '=')
- fprintf(monfile,"\n");
- #endif /* EventMon */
- }
-
- /*
- * evcmd(addr, len, c) - output a memmon command.
- * If addr is < 0, it is omitted.
- * If len matches the previous value for command c, it is also omitted.
- * If the output fills the line, a following newline is written.
- */
-
- static novalue evcmd(addr, len, c)
- word addr, len;
- int c;
- {
- if (!EventStream)
- return;
- if (addr >= 0) {
- evdec((uword)addr);
- evchar(E_Offset);
- }
- etvalue(len, c);
- if (llen >= LLIM)
- evnewline();
- else
- evspace();
- }
-
- /*
- * etvalue(n, c) - output length n with character c.
- * Omit the length if it matches the previous value for c.
- */
- static novalue etvalue(n, c)
- word n;
- int c;
- {
- if (n != curvalue[c-CurBias])
- evdec((uword)(curvalue[c-CurBias] = n));
- evchar(c);
- }
-
- /*
- * evdec(n) - output a decimal value, updating the line length.
- */
- static novalue evdec (n)
- uword n;
- {
- if (n > 9)
- evdec(n / 10);
- n %= 10;
- evchar('0'+(int)n);
- }
-
- /*
- * evnewline() - output a newline and reset the line length.
- */
- static novalue evnewline()
- {
- if (llen > 0) {
- putc('\n', monfile);
- llen = 0;
- }
- }
-
- /*
- * evforget() - clear the history of remembered lengths.
- */
- static novalue evforget()
- {
- int c;
-
- for (c = 0; c < CurSize; c++)
- curvalue[c] = -1;
- }
-
- /*
- * EVVal(value, event) - note value produced for event
- */
-
- novalue EVVal(value, event)
- word value;
- int event;
- {
-
- if (!EventStream)
- return;
- evcmd((word)-1, value, event);
- }
- #ifdef EventMon
- /*
- * EVFnc -- write entry in function symbol table for global j
- */
- novalue EVFnc(j)
- word j;
- {
- if (!EventStream)
- return;
- EVVal(j + 1, E_Pid);
- EVQval(&gnames[j], E_Sym);
- }
- /*
- * EVQval -- Write quoted value from descriptor
- */
- novalue EVQval(dp, j)
- dptr dp;
- int j;
- {
- fprintf(monfile, "\"%s\"%c\n", StrLoc(*dp), j);
- }
-
-
-
- /*
- * EVValD(dp, event) - note descriptor value. For event streams, procedures
- * get mapped into their index in the global descriptor array. For all
- * other types of events, they get mapped into their (event) type code.
- */
-
- novalue EVValD(dp, event)
- dptr dp;
- int event;
- {
-
-
- if (!EventStream)
- return;
- switch (event) {
- case E_Pvan:
- case E_Pcall:
- case E_Presum:
- case E_Psusp:
- case E_Pret:
- case E_Pfail: {
- word i, j;
- /*
- * Scan the global variable array for procedures address
- */
- i = 0;
- for (j = 0; j < n_globals; j++)
- if (BlkLoc(*dp) == BlkLoc(globals[j])) {
- i = j + 1;
- break;
- }
- evcmd((word)-1, i, event);
- return;
- }
- default:
- evcmd((word)-1,TypeCode(*dp),event);
- }
- }
-
- /*
- * EVValX(bp, event) - note co-expression value
- */
-
- novalue EVValX(bp, event)
- struct b_coexpr *bp;
- int event;
- {
-
-
- if (!EventStream)
- return;
- evcmd((word)-1,bp->id,event);
- }
-
- /*
- * EVInt(i) - write value of integer i to the event history file
- */
-
- novalue EVInt(i)
- word i;
- {
- if (!EventStream)
- return;
-
- evdec(i);
- evchar('L'); /* added for syntax confoemance */
- evseparate();
-
- }
-
-
-
- #if UNIX
- /*
- * EVTick() - record a Tick event reflecting a clock advance.
- *
- * The interpreter main loop has detected a change in the profile counters.
- * This means that the system clock has ticked. Record an event and update
- * the records.
- */
- static word oldsum = 0;
-
- novalue EVTick()
- {
- word sum, nticks;
-
- oldtick = ticker.l[0] + ticker.l[1];
- sum = ticker.s[0] + ticker.s[1] + ticker.s[2] + ticker.s[3];
- nticks = sum - oldsum;
- EVVal(nticks, E_Tick);
- oldsum = sum;
- }
- #endif /* UNIX */
- #endif /* EventMon */
-
- #else /* MemMon */
- static char x; /* avoid empty module */
- #endif /* MemMon */
-